package com.lgx.common.alipay.controller;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.lgx.common.alipay.config.AlipayConfig;
import com.lgx.common.alipay.util.AlipayNotify;
import com.lgx.common.alipay.util.AlipayUtils;
import com.lgx.common.exception.DataException;
import com.lgx.common.web.util.DateUtils;
import com.lgx.mall.business.entity.Order;
import com.lgx.mall.business.entity.OrderDetail;
import com.lgx.mall.business.service.IOrderDetailService;
import com.lgx.mall.business.service.IOrderService;
import com.lgx.mall.core.service.IProductService;
import com.lgx.right.dao.ICardDao;
import com.lgx.right.entity.Card;

/**
 * 支付宝控制器
 * 
 * @author acer
 *
 */
@Controller
@RequestMapping("/alipay")
public class AlipayController {

	@Autowired
	private IOrderService orderService;
	
	@Autowired
	private ICardDao cardDao;
	
	@Autowired
	private IOrderDetailService orderDetailService;
	
	@Autowired
	private IProductService productService;

	public IProductService getProductService() {
		return productService;
	}

	public void setProductService(IProductService productService) {
		this.productService = productService;
	}

	public IOrderDetailService getOrderDetailService() {
		return orderDetailService;
	}

	public void setOrderDetailService(IOrderDetailService orderDetailService) {
		this.orderDetailService = orderDetailService;
	}

	public ICardDao getCardDao() {
		return cardDao;
	}

	public void setCardDao(ICardDao cardDao) {
		this.cardDao = cardDao;
	}

	public IOrderService getOrderService() {
		return orderService;
	}

	public void setOrderService(IOrderService orderService) {
		this.orderService = orderService;
	}
	
	protected Logger logger = Logger.getLogger(this.getClass());
	
	/**
	 * 跳转到支付宝
	 * 
	 * @param orderId
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value="/{orderId}.htm",method=RequestMethod.GET)
	public String alipayTo(@PathVariable("orderId") long orderId,HttpServletRequest request,HttpServletResponse response){
		
		String path = request.getContextPath();
		String basePath = request.getScheme() + "://"
				+ request.getServerName() + ":" + request.getServerPort()
				+ path + "/";
		
		Order order = this.orderService.findOrderById(orderId);
		
		//必填参数//
		//请与贵网站订单系统中的唯一订单号匹配
		String out_trade_no = order.getOrderNo();
		//订单名称，显示在支付宝收银台里的“商品名称”里，显示在支付宝的交易管理的“商品名称”的列表里。
		String subject = "订单号"+out_trade_no;
		//订单描述、订单详细、订单备注，显示在支付宝收银台里的“商品描述”里
		String body = "";
		//订单总金额，显示在支付宝收银台里的“应付总额”里
		String price = order.getFare()+"";
		
		//物流费用，即运费。
		String logistics_fee = "0.00";
		//物流类型，三个值可选：EXPRESS（快递）、POST（平邮）、EMS（EMS）
		String logistics_type = "EXPRESS";
		//物流支付方式，两个值可选：SELLER_PAY（卖家承担运费）、BUYER_PAY（买家承担运费）
		String logistics_payment = "BUYER_PAY";
		
		//商品数量，建议默认为1，不改变值，把一次交易看成是一次下订单而非购买一件商品。
		String quantity = "1";

		//////////////////////////////////////////////////////////////////////////////////
		logger.debug("send payment request[Order ID:"+order.getOrderNo()+" "+order.getFare()+"]");
		
		
		//把请求参数打包成数组
		Map<String, String> sParaTemp = new HashMap<String, String>();
		sParaTemp.put("payment_type","1");
		sParaTemp.put("show_url", "");
		sParaTemp.put("out_trade_no", out_trade_no);
		sParaTemp.put("subject", subject);
		sParaTemp.put("body", body);
		sParaTemp.put("price", price);
		sParaTemp.put("logistics_fee", logistics_fee);
		sParaTemp.put("logistics_type", logistics_type);
		sParaTemp.put("logistics_payment", logistics_payment);
		sParaTemp.put("quantity", quantity);
		sParaTemp.put("receive_name", order.getConsigneeName());
		sParaTemp.put("receive_address", order.getProvince()+order.getCity()+order.getRegion()+order.getAddress());
		sParaTemp.put("receive_zip", order.getZipcode());
		sParaTemp.put("receive_phone", "");
		sParaTemp.put("receive_mobile", order.getConsigneeTel());
		
		//设置AlipayConfig.return_url
		AlipayConfig.return_url = basePath + "alipay/return_url.htm";
		//设置AlipayConfig.notify_url
		AlipayConfig.notify_url = basePath + "alipay/notify_url.htm";
		
		//构造函数，生成请求URL
		String sHtmlText = AlipayUtils.trade_create_by_buyer(sParaTemp);
		
		request.setAttribute("sHtmlText", sHtmlText);
		
		return "alipay/alipayto";
	}
	
	/**
	 * 支付宝服务器异步通知
	 * 
	 *  WAIT_BUYER_PAY(表示买家已在支付宝交易管理中产生了交易记录，但没有付款);
	 *  WAIT_SELLER_SEND_GOODS(表示买家已在支付宝交易管理中产生了交易记录且付款成功，但卖家没有发货);
	 *  WAIT_BUYER_CONFIRM_GOODS(表示卖家已经发了货，但买家还没有做确认收货的操作);
	 *  TRADE_FINISHED(表示买家已经确认收货，这笔交易完成);
	 *  
	 *  不能在本机电脑测试，请到服务器上做测试。请确保外部可以访问该页面。
	 *  调试工具请使用写文本函数logResult，该函数在com.alipay.util文件夹的AlipayNotify.java类文件中
	 *  如果没有收到该页面返回的 success 信息，支付宝会在24小时内按一定的时间策略重发通知
	 *  
	 * @param request
	 * @param response
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	@SuppressWarnings("rawtypes")
	@RequestMapping("/notify_url.htm")
	public void notify_url(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException{
		
		PrintWriter out = null;
		try {
			out = response.getWriter();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		String path = request.getContextPath();
		String basePath = request.getScheme() + "://"
				+ request.getServerName() + ":" + request.getServerPort()
				+ path + "/";
		request.setAttribute("basePath", basePath);
		
		//获取支付宝POST过来反馈信息
		Map<String,String> params = new HashMap<String,String>();
		Map requestParams = request.getParameterMap();
		for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = (String) iter.next();
			String[] values = (String[]) requestParams.get(name);
			String valueStr = "";
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i]
						: valueStr + values[i] + ",";
			}
			//乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
			valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
			params.put(name, valueStr);
		}
		
		//获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
		String trade_no = request.getParameter("trade_no");				//支付宝交易号
		String order_no = request.getParameter("out_trade_no");	        //获取订单号
		
		String trade_status = request.getParameter("trade_status");		//交易状态
		
		//获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//

		Order order = null;
		
		if(!StringUtils.isEmpty(order_no)){
			order = this.orderService.findOrderByOrderNo(order_no);
		}
		
		request.setAttribute("trade_status", trade_status);
		request.setAttribute("trade_no", trade_no);
		request.setAttribute("order_no", order_no);
		
		if(AlipayNotify.verify(params)){//验证成功
			//////////////////////////////////////////////////////////////////////////////////////////
			//请在这里加上商户的业务逻辑程序代码
			
			//——请根据您的业务逻辑来编写程序（以下代码仅作参考）——
			
			if(trade_status.equals("WAIT_BUYER_PAY")){
				//该判断表示买家已在支付宝交易管理中产生了交易记录，但没有付款
				
				//判断该笔订单是否在商户网站中已经做过处理（可参考“集成教程”中“3.4返回数据处理”）
				//如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
				//如果有做过处理，不执行商户的业务程序
				if(order != null){
					//判断是否已产生了交易记录
					if(order.getStatus() < 1){
						order.setStatus(1);
						order.setTradeNo(trade_no);
						this.orderService.updateOrder(order);
					}
				}
				
				out.println("success");	//请不要修改或删除
			} else if(trade_status.equals("WAIT_SELLER_SEND_GOODS")){
				//该判断表示买家已在支付宝交易管理中产生了交易记录且付款成功，但卖家没有发货
				
				//判断该笔订单是否在商户网站中已经做过处理（可参考“集成教程”中“3.4返回数据处理”）
				//如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
				//如果有做过处理，不执行商户的业务程序
				if(order != null){
					//判断是否已付款
					if(order.getStatus() < 2){
						Card card = order.getUser().getCard();
						card.setScore(card.getScore()-order.getScore());
						try {
							//更新卡号积分
							this.cardDao.updateCard(card);
							logger.info("卡号["+card.getId()+"],扣除积分："+order.getScore()+"操作成功！");
						} catch (DataException e) {
							e.printStackTrace();
							logger.info("卡号["+card.getId()+"],扣除积分："+order.getScore()+"操作失败！");
						}
						
						List<OrderDetail> details = this.orderDetailService.findOrderDetailList(order.getId());
						
						//修改商品的库存
						for(OrderDetail detail : details){
							if("com.lgx.mall.core.entity.Product".equals(detail.getEntityType())){
								this.productService.modifyProductInventory(detail.getEntityId(), detail.getAmount(), "-");
								
								logger.info("修改库存["+detail.getEntityId()+"]:-"+detail.getAmount());
							}
						}
						
						order.setStatus(2);
						order.setPayTime(new Date());
						order.setTradeNo(trade_no);
						this.orderService.updateOrder(order);
					}
				}	
				
				out.println("success");	//请不要修改或删除
			} else if(trade_status.equals("WAIT_BUYER_CONFIRM_GOODS")){
				//该判断表示卖家已经发了货，但买家还没有做确认收货的操作
				
				//判断该笔订单是否在商户网站中已经做过处理（可参考“集成教程”中“3.4返回数据处理”）
				//如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
				//如果有做过处理，不执行商户的业务程序
				if(order != null){
					//该判断表示卖家已经发了货
					if(order.getStatus() < 3){
						order.setStatus(3);
						order.setTradeNo(trade_no);
						this.orderService.updateOrder(order);
					}
				}		
				
				out.println("success");	//请不要修改或删除
			} else if(trade_status.equals("TRADE_FINISHED")){
				//该判断表示买家已经确认收货，这笔交易完成
				
				//判断该笔订单是否在商户网站中已经做过处理（可参考“集成教程”中“3.4返回数据处理”）
				//如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
				//如果有做过处理，不执行商户的业务程序
				if(order != null){
					//该判断表示买家已经确认收货
					if(order.getStatus() < 4){
						order.setStatus(4);
						order.setTradeNo(trade_no);
						this.orderService.updateOrder(order);
					}
				}			
				
				out.println("success");	//请不要修改或删除
			}else {
				
				out.println("success");	//请不要修改或删除
			}

			//——请根据您的业务逻辑来编写程序（以上代码仅作参考）——

			//////////////////////////////////////////////////////////////////////////////////////////
		}else{//验证失败
			
			out.println("fail");
		}
		
		//return "alipay/notify_url";
	}
	
	/**
	 * 支付宝页面跳转同步通知
	 *  WAIT_BUYER_PAY(表示买家已在支付宝交易管理中产生了交易记录，但没有付款);
	 *  WAIT_SELLER_SEND_GOODS(表示买家已在支付宝交易管理中产生了交易记录且付款成功，但卖家没有发货);
	 *  WAIT_BUYER_CONFIRM_GOODS(表示卖家已经发了货，但买家还没有做确认收货的操作);
	 *  TRADE_FINISHED(表示买家已经确认收货，这笔交易完成);
	 *  
	 *  可在本机电脑测试
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	@SuppressWarnings("rawtypes")
	@RequestMapping("/return_url.htm")
	public String return_url(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException{
		
		PrintWriter out = null;
		try {
			out = response.getWriter();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		String path = request.getContextPath();
		String basePath = request.getScheme() + "://"
				+ request.getServerName() + ":" + request.getServerPort()
				+ path + "/";
		request.setAttribute("basePath", basePath);
		
		//获取支付宝GET过来反馈信息
		Map<String,String> params = new HashMap<String,String>();
		Map requestParams = request.getParameterMap();
		for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = (String) iter.next();
			String[] values = (String[]) requestParams.get(name);
			String valueStr = "";
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i]
						: valueStr + values[i] + ",";
			}
			//乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
			valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
			params.put(name, valueStr);
		}
		
		
		//获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
		String trade_no = request.getParameter("trade_no");				//支付宝交易号
		String order_no = request.getParameter("out_trade_no");	        //获取订单号
		
		String trade_status = request.getParameter("trade_status");		//交易状态
		
		//获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
		
		//计算得出通知验证结果
		boolean verify_result = AlipayNotify.verify(params);
		
		Order order = null;
		
		if(!StringUtils.isEmpty(order_no)){
			order = this.orderService.findOrderByOrderNo(order_no);
		}
		
		if(verify_result){//验证成功
			//////////////////////////////////////////////////////////////////////////////////////////
			//请在这里加上商户的业务逻辑程序代码

			//——请根据您的业务逻辑来编写程序（以下代码仅作参考）——
			if(trade_status.equals("WAIT_SELLER_SEND_GOODS")){
				//判断该笔订单是否在商户网站中已经做过处理（可参考“集成教程”中“3.4返回数据处理”）
				//如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
				//如果有做过处理，不执行商户的业务程序
				if(order != null){
					//判断是否已付款
					if(order.getStatus() < 2){
						Card card = order.getUser().getCard();
						card.setScore(card.getScore()-order.getScore());
						try {
							//更新卡号积分
							this.cardDao.updateCard(card);
							logger.info("卡号["+card.getId()+"],扣除积分："+order.getScore()+"操作成功！");
						} catch (DataException e) {
							e.printStackTrace();
							logger.info("卡号["+card.getId()+"],扣除积分："+order.getScore()+"操作失败！");
						}
						
						List<OrderDetail> details = this.orderDetailService.findOrderDetailList(order.getId());
						
						//修改商品的库存
						for(OrderDetail detail : details){
							if("com.lgx.mall.core.entity.Product".equals(detail.getEntityType())){
								this.productService.modifyProductInventory(detail.getEntityId(), detail.getAmount(), "-");
								
								logger.info("修改库存["+detail.getEntityId()+"]:-"+detail.getAmount());
							}
						}
						
						order.setStatus(2);
						order.setPayTime(new Date());
						order.setTradeNo(trade_no);
						this.orderService.updateOrder(order);
					}
				}
				
			}else if(trade_status.equals("TRADE_FINISHED")){
				//该判断表示买家已经确认收货，这笔交易完成
				
				//判断该笔订单是否在商户网站中已经做过处理（可参考“集成教程”中“3.4返回数据处理”）
				//如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
				//如果有做过处理，不执行商户的业务程序
				
				if(order != null){
					//判断是否已确认
					if(order.getStatus() < 4){
						order.setStatus(4);
						order.setTradeNo(trade_no);
						this.orderService.updateOrder(order);
					}
				}
			}
			
			//该页面可做页面美工编辑
			out.println("验证成功<br />");
			out.println("trade_no=" + trade_no);
			
			//——请根据您的业务逻辑来编写程序（以上代码仅作参考）——
			
			request.setAttribute("trade_status", trade_status);
			request.setAttribute("trade_no", trade_no);
			request.setAttribute("order_no", order_no);
			request.setAttribute("vaildate_msg", "验证成功");

			//////////////////////////////////////////////////////////////////////////////////////////
		}else{
			//该页面可做页面美工编辑
			out.println("验证失败");
			request.setAttribute("vaildate_msg", "验证失败");
		}
		return "alipay/return_url";
	}
	
	/**
	 * 确认发货
	 * 
	 * @param orderId
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception 
	 */
	@RequestMapping(value="/confirm/{orderId}.htm",method=RequestMethod.GET)
	public String send_goods_confirm(@PathVariable("orderId") long orderId,HttpServletRequest request,HttpServletResponse response) throws Exception{
		
		String path = request.getContextPath();
		String basePath = request.getScheme() + "://"
				+ request.getServerName() + ":" + request.getServerPort()
				+ path + "/";
		
		Order order = this.orderService.findOrderById(orderId);
		
		//必填参数//
		//支付宝交易号
		String trade_no = request.getParameter("trade_no");
		
		//物流公司名称
		String logistics_name = request.getParameter("logistics_name");
		
		//发货时的运输类型
		String transport_type = "EXPRESS";
		
		//选填参数
		
        //物流发货单号
		String invoice_no = request.getParameter("invoice_no");
		
		order.setExpcom(logistics_name);
		order.setExpNo(invoice_no);
		order.setExpDate(DateUtils.dateToChar(new Date(), DateUtils.DATE_FORMAT_T));
		
		this.orderService.updateOrder(order);
		//////////////////////////////////////////////////////////////////////////////////
		
		//把请求参数打包成数组
		Map<String, String> sParaTemp = new HashMap<String, String>();
        sParaTemp.put("trade_no", trade_no);
        sParaTemp.put("logistics_name", logistics_name);
		sParaTemp.put("invoice_no", invoice_no);
		sParaTemp.put("transport_type", transport_type);

		//请在这里加上商户的业务逻辑程序代码

		//——请根据您的业务逻辑来编写程序（以下代码仅作参考）——

		//获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表

		//out.println(sHtmlText);

        //——请根据您的业务逻辑来编写程序（以上代码仅作参考）——

		//////////////////////////////////////////////////////////////////////////////////
		logger.debug("send_goods_confirm_by_platform[Order ID:"+order.getOrderNo()+" "+order.getFare()+"]");
		
		//设置AlipayConfig.return_url
		AlipayConfig.return_url = basePath + "alipay/return_url.htm";
		//设置AlipayConfig.notify_url
		AlipayConfig.notify_url = basePath + "alipay/notify_url.htm";
		
		//构造函数，生成请求URL  
		String sHtmlText = AlipayUtils.send_goods_confirm_by_platform(sParaTemp);
		
		request.setAttribute("sHtmlText", sHtmlText);
		
		return "alipay/send_goods_confirm_by_platform";
	}
}
